#include "stdafx.h"
#include "MouseTracerManagerImpl4.h"
#include "MouseTracer.h"
#include "MGCfg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

HHOOK CMouseTracerManagerImpl4::m_hHookMouse = NULL;
HHOOK CMouseTracerManagerImpl4::m_hHookCallWndRet = NULL;
CMouseTracer<CMouseTracerManager<CMouseTracerManagerImpl4> > *CMouseTracerManagerImpl4::m_pTracer = NULL;

CMouseTracerManagerImpl4::CMouseTracerManagerImpl4()
{
}

CMouseTracerManagerImpl4::~CMouseTracerManagerImpl4()
{
	if (m_hHookCallWndRet)
	{
		::UnhookWindowsHookEx(m_hHookCallWndRet);
		m_hHookCallWndRet = NULL;
	}
	
	if (m_hHookMouse)
	{
		::UnhookWindowsHookEx(m_hHookMouse);
		m_hHookMouse = NULL;
	}
	
	// m_pTracer will be automatically deleted on receiving WM_NCDESTROY
}

/**
*	CMouseTracerManagerImpl4::Setup(HINSTANCE hMod)
*
*
*	@return BOOL
*
*/

BOOL CMouseTracerManagerImpl4::Setup(HINSTANCE hMod)
{
	if (m_hHookMouse && m_hHookCallWndRet)
		return TRUE;
	
	if(hMod == NULL)
		hMod = (HINSTANCE)::GetModuleHandle(NULL);
	
	if(m_hHookMouse == NULL)
		m_hHookMouse = ::SetWindowsHookEx(WH_MOUSE, MouseProc, hMod, ::GetCurrentThreadId());
	
	if(m_hHookCallWndRet == NULL)
		m_hHookCallWndRet = ::SetWindowsHookEx(WH_CALLWNDPROCRET, CallWndProcRet, hMod, ::GetCurrentThreadId());
	
	
	return !(m_hHookMouse == NULL || m_hHookCallWndRet == NULL);
}

/**
*	CMouseTracerManagerImpl4::Remove()
*
*
*	@return void
*
*/

void CMouseTracerManagerImpl4::Remove()
{
	if (m_hHookMouse)
	{
		::UnhookWindowsHookEx(m_hHookMouse);
		m_hHookMouse = NULL;
	}
	
	if (m_hHookCallWndRet)
	{
		::UnhookWindowsHookEx(m_hHookCallWndRet);
		m_hHookCallWndRet = NULL;
	}
	
	if (m_pTracer)
	{
		if (::IsWindow(m_pTracer->m_hWnd))
		{
			m_pTracer->Unhook();
			delete m_pTracer;
			m_pTracer = NULL;
		}
	}
}


LRESULT CALLBACK CMouseTracerManagerImpl4::MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
	if(nCode < 0)
		return ::CallNextHookEx(m_hHookMouse, nCode, wParam, lParam);
	
    if (nCode == HC_ACTION)
    {
        if (lParam)
        {
#if(_WIN32_WINNT >= 0x0500)
            MOUSEHOOKSTRUCTEX *pMHEX = reinterpret_cast<MOUSEHOOKSTRUCTEX *>(lParam);
			MOUSEHOOKSTRUCT *pMH = (MOUSEHOOKSTRUCT *)pMHEX;
#else	// #if(_WIN32_WINNT >= 0x0500)
            MOUSEHOOKSTRUCT *pMH = reinterpret_cast<MOUSEHOOKSTRUCT *>(lParam);
#endif	// #if(_WIN32_WINNT >= 0x0500)
			
			int nCatTarget;
			switch (wParam)
			{
			case WM_RBUTTONDOWN:
			case WM_NCRBUTTONDOWN:
				if (MGCfg::Get().Option().GetMGAButton() == MG::BUTTON_RIGHT)
				{
					if ((m_pTracer && !m_pTracer->IsTemporarySuspended()) || !m_pTracer)
					{
						if (m_pTracer && MGCfg::Get().Option().IsShowRecognitionOnStatusBar() && MGCfg::Get().Option().IsIdentifyTargetWindowClass())
							MGCfg::Get().Action().IdentifyTargetWindowClass(pMH->hwnd);
						
						if ((nCatTarget = MGCfg::Get().Action().CheckTargetValid(pMH->hwnd)) != -1)
						{
							if (m_pTracer)
							{
								if (m_pTracer->m_hWnd != pMH->hwnd)
								{
									// check to see if the hooked window have already been destoroyed
									if (::IsWindow(m_pTracer->m_hWnd))
									{
										m_pTracer->Unhook();
										delete m_pTracer;
										m_pTracer = NULL;
									}
								}
								else 
									break;
							}
							m_pTracer = (CMouseTracer<CMouseTracerManager<CMouseTracerManagerImpl4> > *)new CMouseTracer<CMouseTracerManager<CMouseTracerManagerImpl4> >(TRUE);
							m_pTracer->Hook(pMH->hwnd);
							m_pTracer->SetTargetCategory((BYTE)nCatTarget);
						}
					}
				}
				break;
				
			case WM_MBUTTONDOWN:
			case WM_NCMBUTTONDOWN:
				if (MGCfg::Get().Option().GetMGAButton() == MG::BUTTON_MIDDLE)
				{
					if ((m_pTracer && !m_pTracer->IsTemporarySuspended()) || !m_pTracer)
					{
						if (m_pTracer && MGCfg::Get().Option().IsShowRecognitionOnStatusBar() && MGCfg::Get().Option().IsIdentifyTargetWindowClass())
							MGCfg::Get().Action().IdentifyTargetWindowClass(pMH->hwnd);
						
						if ((nCatTarget = MGCfg::Get().Action().CheckTargetValid(pMH->hwnd)) != -1)
						{
							if (m_pTracer)
							{
								if (m_pTracer->m_hWnd != pMH->hwnd)
								{
									if (::IsWindow(m_pTracer->m_hWnd))
									{
										m_pTracer->Unhook();
										delete m_pTracer;
										m_pTracer = NULL;
									}
								}
								else 
									break;
							}
							m_pTracer = (CMouseTracer<CMouseTracerManager<CMouseTracerManagerImpl4> > *)new CMouseTracer<CMouseTracerManager<CMouseTracerManagerImpl4> >(TRUE);
							m_pTracer->Hook(pMH->hwnd);
							m_pTracer->SetTargetCategory((BYTE)nCatTarget);
							TRACE("%s to install a mouse tracer to (%x)\n", m_pTracer ? _T("Succeeded") : _T("Failed"), pMH->hwnd);
						}
					}
				}
				break;
				
			case WM_RBUTTONDBLCLK:
			case WM_LBUTTONDBLCLK:
			case WM_MBUTTONDBLCLK:
				if ((nCatTarget = MGCfg::Get().Action().CheckTargetValid(pMH->hwnd)) != -1)
				{
					if ((m_pTracer && !m_pTracer->HasMouseCapture()) || !m_pTracer)
					{
						if (m_pTracer)
						{
							if (m_pTracer->m_hWnd != pMH->hwnd)
							{
								if (::IsWindow(m_pTracer->m_hWnd))
								{
									HWND hWnd = m_pTracer->Unhook();
									delete m_pTracer;
									m_pTracer = NULL;
									TRACE2("%s to remove a mouse tracer from (%x)\n", hWnd ? _T("Succeeded") : _T("Failed"), hWnd);
								}
							}
							else 
								break;
						}
						m_pTracer = (CMouseTracer<CMouseTracerManager<CMouseTracerManagerImpl4> > *)new CMouseTracer<CMouseTracerManager<CMouseTracerManagerImpl4> >(TRUE);
						m_pTracer->Hook(pMH->hwnd);
						m_pTracer->SetTargetCategory((BYTE)nCatTarget);
						TRACE2("%s to install a mouse tracer to (%x)\n", m_pTracer ? _T("Succeeded") : _T("Failed"), pMH->hwnd);
					}
				}
				break;
			}
		}
    }
	
	return ::CallNextHookEx(m_hHookMouse, nCode, wParam, lParam);
}

LRESULT CALLBACK CMouseTracerManagerImpl4::CallWndProcRet(int nCode, WPARAM wParam, LPARAM lParam)
{
	if(nCode < 0)
		return ::CallNextHookEx(m_hHookCallWndRet, nCode, wParam, lParam);
	
	
    if (nCode == HC_ACTION)
    {
        if (lParam)
        {
            CWPRETSTRUCT *pCWPR = reinterpret_cast<CWPRETSTRUCT *>(lParam);
			
			switch (pCWPR->message)
			{
			case WM_KILLFOCUS:
				if( m_pTracer && m_pTracer->m_hWnd == pCWPR->hwnd && ::IsWindow(m_pTracer->m_hWnd) )
				{
					m_pTracer->PostMessageUnhookAndDelete();
					//	delete m_pTracer;
					m_pTracer = NULL;
					TRACE0("WM_KILLFOCUS-PostMessageUnhook( TRUE(bAutoDeleteAfterUnhook) )\n");
				}
				break;
			}
		}
    }
	
	return ::CallNextHookEx(m_hHookCallWndRet, nCode, wParam, lParam);
}
